package xyz.bali16.module.team.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.bali16.application.core.enums.ApiEnum;
import xyz.bali16.application.core.model.Result;
import xyz.bali16.application.core.utils.AuthUtils;
import xyz.bali16.application.core.utils.TimeUtil;
import xyz.bali16.application.entity.User;
import xyz.bali16.application.service.UserService;
import xyz.bali16.module.team.entity.Team;
import xyz.bali16.module.team.entity.UserTeam;
import xyz.bali16.module.team.enums.TeamStatusEnum;
import xyz.bali16.module.team.mapper.TeamMapper;
import xyz.bali16.module.team.model.TeamAddParam;
import xyz.bali16.module.team.model.TeamPageParam;
import xyz.bali16.module.team.model.TeamUpdateParam;
import xyz.bali16.module.team.model.request.TeamJoinRequest;
import xyz.bali16.module.team.model.request.TeamQuitRequest;
import xyz.bali16.module.team.model.vo.TeamUserVO;
import xyz.bali16.module.team.model.vo.UserVO;

import java.text.ParseException;
import java.util.*;

@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team> implements TeamService {

    @Autowired
    private TeamMapper teamMapper;

    @Autowired
    @AutowiredType(AutowiredType.Type.PLUGIN_MAIN)
    private UserService userService;

    @Autowired
    private UserTeamService userTeamService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> addTeam(TeamAddParam teamAddParam) throws ParseException {
        String username = AuthUtils.getCurrentUsername();
        User user = userService.getByUsername(username);
        // 1 请求参数为空
        if (teamAddParam == null) {
            return Result.failure(ApiEnum.ERROR);
        }
        // 2 用户是否登录
        if (username == null || user == null) {
            return Result.failure(ApiEnum.NOT_LOGIN);
        }
        // 3 检验信息
        // (1) 队伍人数 > 1 && 队伍人数 < 20
        int maxNum = Optional.ofNullable(teamAddParam.getMaxNum()).orElse(0);
        if (maxNum < 1 || maxNum > 20) {
            return Result.failure("队伍人数不满足要求");
        }
        // (2) 队伍名 <= 20
        String name = teamAddParam.getName();
        if (StringUtils.isBlank(name) || name.length() > 20) {
            return Result.failure("队伍标题不满足要求");
        }
        // 3 描述长度 <= 512
        String description = teamAddParam.getDescription();
        if (description.length() > 512 || StringUtils.isBlank(description)) {
            return Result.failure("队伍描述长度过长");
        }
        // 4 队伍状态是否公开，不传默认为零
        int status = Optional.ofNullable(teamAddParam.getStatus()).orElse(0);
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
        if (statusEnum == null) {
            return Result.failure("队伍状态不满足要求");
        }
        // 5 如果status是加密状态，一定要用密码，且密码 <= 32
        String password = teamAddParam.getPassword();
        if (TeamStatusEnum.SCRECT.equals(statusEnum)) {
            if (StringUtils.isBlank(password) || password.length() > 32) {
                return Result.failure("密码设置不正确");
            }
        }
        // 6 超出时间 > 当前时间
        Date expireTime = TimeUtil.getDateByString(teamAddParam.getExpireTime(), TimeUtil.FORMAT_SECONDS);
        if (new Date().after(expireTime)) {
            return Result.failure("超出时间大于当前时间");
        }
        String userId = user.getUserId();
        // 7 校验用户最多创建5个队伍
        LambdaQueryWrapper<Team> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(Team::getUserId, userId);
        long hasTeamNum = this.count(queryWrapper);
        // 当我创建第五个队伍时，数据库中存储了四个队伍数量
        if (hasTeamNum >= 5) {
            return Result.failure("用户最多创建5个队伍");
        }
        // 8 插入队伍消息到信息列表
        //teamAddParam.setId(null);
        teamAddParam.setUserId(userId);
        Team team = new Team();
        team.setGmtCreated(TimeUtil.getNowTimeToSeconds());
        team.setGmtUpdated(TimeUtil.getNowTimeToSeconds());
        BeanUtils.copyProperties(teamAddParam,team);

        Boolean save = this.save(team);
        Long teamId = team.getId();
        if (!save || teamAddParam == null) {
            return Result.failure("创建队伍失败");
        }
        // 9 插入用户 ==> 队伍关系 到关系表
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(teamId);
        userTeam.setGmtCreated(TimeUtil.getNowTimeToSeconds());
        userTeam.setGmtUpdated(TimeUtil.getNowTimeToSeconds());
        userTeam.setJoinTime(TimeUtil.getNowTimeToSeconds());
        Boolean res = userTeamService.save(userTeam);
        if (!res) {
            return Result.failure("创建队伍失败");
        }
        return Result.success(String.valueOf(teamId));
    }

    @Override
    public List<TeamUserVO> listTeams(TeamPageParam teamPageParam, boolean isAdmin) {
        QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
        //组合查询条件
        if (teamPageParam != null) {
            Long id = teamPageParam.getId();
            if (id != null && id > 0) {
                queryWrapper.eq("id", id);
            }
            List<Long> idList = teamPageParam.getIdList();
            if (CollectionUtils.isNotEmpty(idList)) {
                queryWrapper.in("id", idList);
            }
            String searchText = teamPageParam.getSearchText();
            if (StringUtils.isNotBlank(searchText)) {
                queryWrapper.and(qw -> qw.like("name", searchText).or().like("expire_time", searchText));
            }
            String name = teamPageParam.getName();
            if (StringUtils.isNotBlank(name)) {
                queryWrapper.like("name", name);
            }
            String description = teamPageParam.getDescription();
            if (StringUtils.isNotBlank(description)) {
                queryWrapper.like("description", description);
            }
            Integer maxNum = teamPageParam.getMaxNum();
            //查询最大人数相等
            if (maxNum != null && maxNum > 0) {
                queryWrapper.eq("max_num", maxNum);
            }
            String userId = teamPageParam.getUserId();
            //根据创建人来查询
            if (userId != null) {
                queryWrapper.eq("user_id", userId);
            }
            //根据状态来查询
            Integer status = teamPageParam.getStatus();
            TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);
            if (statusEnum == null) {
                statusEnum = TeamStatusEnum.PUBLIC;
            }
            if (!isAdmin && statusEnum.equals(TeamStatusEnum.PRIVATE)) {
                System.out.println("用户权限不足,无法查看私密队伍");
                return new ArrayList<>();
            }
            queryWrapper.eq("status", statusEnum.getValue());
        }

        //不展示已过期的队伍
        //expireTime is null or expireTime > now()
        queryWrapper.and(qw -> qw.gt("expire_time", new Date()).or().isNull("expire_time"));

        List<Team> teamList = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(teamList)) {
            return new ArrayList<>();
        }
        List<TeamUserVO> teamUserVOList = new ArrayList<>();
        //关联查询创建人的用户信息
        for (Team team : teamList) {
            String userId = team.getUserId();
            if (userId == null) {
                continue;
            }
            User user = userService.getById(userId);
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team, teamUserVO);
            //脱敏用户信息
            if (user != null) {
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(user, userVO);
                teamUserVO.setCreateUser(userVO);
            }
            teamUserVOList.add(teamUserVO);
        }
        return teamUserVOList;
    }

    @Override
    public Result<Boolean> updateTeam(TeamUpdateParam teamUpdateParam) {
        String username = AuthUtils.getCurrentUsername();
        User user = userService.getByUsername(username);

        if (teamUpdateParam == null) {
            return Result.failure("参数缺失");
        }

        if (username == null || user == null) {
            return Result.failure(ApiEnum.NOT_LOGIN);
        }

        Long id = teamUpdateParam.getId();
        if (id == null || id <= 0) {
            return Result.failure("参数错误");
        }
        Team oldTeam = this.getById(id);
        if (oldTeam == null) {
            return Result.failure("队伍不存在");
        }

        String creatorId = oldTeam.getUserId();

        String createor = user.getUserId();
        if (!creatorId.equals(createor)) {
            return Result.failure("权限不足");
        }
        // 是管理员或者是创建者才能修改
        /*if(oldTeam.getUserId() != loginUser.getId()) {
            log.info("getUserid==> ",oldTeam.getUserId());
            log.info("getId==> ",loginUser.getId());
            return Result.failure(ApiEnum.NO_AUTH);
        }*/
        TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(teamUpdateParam.getStatus());
        if (statusEnum.equals(TeamStatusEnum.SCRECT)) {
            if (StringUtils.isBlank(teamUpdateParam.getPassword())) {
                return Result.failure("加密房间必须设置密码");
            }
        }
        Team updateTeam = new Team();
        updateTeam.setGmtUpdated(TimeUtil.getNowTimeToSeconds());
        BeanUtils.copyProperties(teamUpdateParam, updateTeam);
        return Result.success(this.updateById(updateTeam));
    }

    @Override
    public Result<Boolean> joinTeam(TeamJoinRequest teamJoinRequest) throws ParseException {
        String username = AuthUtils.getCurrentUsername();
        User user = userService.getByUsername(username);

        if (teamJoinRequest == null) {
            return Result.failure("参数缺失");
        }

        if (username == null || user == null) {
            return Result.failure(ApiEnum.NOT_LOGIN);
        }
        Long teamId = teamJoinRequest.getTeamId();
        Team team = getTeamById(teamId);
        Date expireTime = team.getExpireTime();
        if (expireTime != null && expireTime.before(new Date())) {
            return Result.failure("队伍已过期");
        }
        Integer status = team.getStatus();
        TeamStatusEnum teamStatusEnum = TeamStatusEnum.getEnumByValue(status);
        if (TeamStatusEnum.PRIVATE.equals(teamStatusEnum)) {
            return Result.failure("禁止加入私有队伍");
        }
        String password = teamJoinRequest.getPassword();
        if (TeamStatusEnum.SCRECT.equals(teamStatusEnum)) {
            if (StringUtils.isBlank(password) || !password.equals(team.getPassword())) {
                return Result.failure("密码错误");
            }
        }
        String userId = user.getUserId();
        System.out.println("getLock: " + Thread.currentThread().getId());
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("user_id", userId);
        long hasJoinNum = userTeamService.count(userTeamQueryWrapper);
        if (hasJoinNum > 5) {
            return Result.failure("最多创建和加入 5 个队伍");
        }
        // 不能重复加入已加入的队伍
        userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("user_id", userId);
        userTeamQueryWrapper.eq("team_id", teamId);
        long hasUserJoinTeam = userTeamService.count(userTeamQueryWrapper);
        if (hasUserJoinTeam > 0) {
            return Result.failure("用户已加入该队伍");
        }
        // 已加入队伍的人数
        long teamHasJoinNum = this.countTeamUserByTeamId(teamId);
        if (teamHasJoinNum >= team.getMaxNum()) {
            return Result.failure("队伍已满");
        }
        // 修改队伍信息
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(userId);
        userTeam.setTeamId(teamId);
        userTeam.setJoinTime(TimeUtil.getNowTimeToMs());
        return Result.success(userTeamService.save(userTeam));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> quitTeam(TeamQuitRequest teamQuitRequest) {
        String username = AuthUtils.getCurrentUsername();
        User user = userService.getByUsername(username);

        if (teamQuitRequest == null) {
            return Result.failure("参数缺失");
        }
        if (username == null || user == null) {
            return Result.failure(ApiEnum.NOT_LOGIN);
        }
        Long teamId = teamQuitRequest.getTeamId();
        if (teamId == null || teamId <= 0) {
            return Result.failure("参数错误");
        }
        Team team = this.getById(teamId);
        if (team == null) {
            return Result.failure("队伍不存在");
        }
        String userId = user.getUserId();
        // 更新用户队伍关系表
        UserTeam queryUserTeam = new UserTeam();
        queryUserTeam.setTeamId(teamId);
        queryUserTeam.setUserId(userId);
        //
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>(queryUserTeam);
        long count = userTeamService.count(queryWrapper);
        if (count == 0) {
            return Result.failure("未加入队伍");
        }
        long teamHasJoinNum = this.countTeamUserByTeamId(teamId);
        // 队伍只剩下一个人时，解散队伍
        if (teamHasJoinNum == 1) {
            // 删除队伍
            this.removeById(teamId);
        } else {
            // 队伍至少还剩下两个人
            // 是队长
            if (team.getUserId().equals(userId)) {
                // 把队伍转移给最早加入的用户
                // 1.查询已加入队伍的所有用户和加入时间
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                userTeamQueryWrapper.eq("team_id", teamId);
                userTeamQueryWrapper.last("order by id asc limit 2");
                List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                if (CollectionUtils.isEmpty(userTeamList) || userTeamList.size() <= 1) {
                    return Result.failure(ApiEnum.ERROR);
                }
                // 将队伍转移给下一个人
                UserTeam nextUserTeam = userTeamList.get(1);
                String nextTeamLeaderId = nextUserTeam.getUserId();
                // 更新当前队伍的队长
                Team updateTeam = new Team();
                updateTeam.setId(teamId);
                updateTeam.setUserId(nextTeamLeaderId);
                Boolean result = this.updateById(updateTeam);
                if (!result) {
                    return Result.failure("更新队伍队长失败");
                }
            }
        }
        // 移除关系
        return Result.success(userTeamService.remove(queryWrapper));
    }

    /**
     * 根据 id 获取队伍信息
     *
     * @param teamId
     * @return
     */
    private Team getTeamById(Long teamId) {
        if (teamId == null || teamId <= 0) {
            return null;
        }
        Team team = this.getById(teamId);
        if (team == null) {
            return null;
        }
        return team;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> deleteTeam(Long id) {
        String username = AuthUtils.getCurrentUsername();
        User user = userService.getByUsername(username);

        if (username == null || user == null) {
            return Result.failure(ApiEnum.NOT_LOGIN);
        }
        // 校验队伍是否存在
        Team team = getTeamById(id);
        long teamId = team.getId();
        // 校验你是不是队长
        if (!team.getUserId().equals(user.getUserId())) {
            return Result.failure("无权限访问");
        }
        // 移出队伍相关信息，删除在关系表里的用户和队伍
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("team_id", teamId);
        Boolean result = userTeamService.remove(userTeamQueryWrapper);
        if (!result) {
            return Result.failure("删除队伍关联信息失败");
        }
        // 删除队伍表中的队伍信息
        return Result.success(this.removeById(teamId));
    }

    /**
     * 获取当前队伍人数
     */
    private long countTeamUserByTeamId(Long teamId) {
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("team_id", teamId);
        return userTeamService.count(userTeamQueryWrapper);
    }


    //@Override
    //public List<User> matchUsers(long num, User loginUser) {
    //    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //    queryWrapper.select("id", "tags");
    //    queryWrapper.isNotNull("tags");
    //    List<User> userList = this.list(queryWrapper);
    //    String tags = loginUser.getTags();
    //    Gson gson = new Gson();
    //    List<String> tagList = gson.fromJson(tags, new TypeToken<List<String>>() {
    //    }.getType());
    //    // 用户列表的下标 => 相似度
    //    List<Pair<User, Long>> list = new ArrayList<>();
    //    // 依次计算所有用户和当前用户的相似度
    //    for (int i = 0; i < userList.size(); i++) {
    //        User user = userList.get(i);
    //        String userTags = user.getTags();
    //        // 无标签或者为当前用户自己
    //        if (StringUtils.isBlank(userTags) || user.getId().equals(loginUser.getId())) {
    //            continue;
    //        }
    //        List<String> userTagList = gson.fromJson(userTags, new TypeToken<List<String>>() {
    //        }.getType());
    //        // 计算分数
    //        long distance = AlgorithmUtils.minDistance(tagList, userTagList);
    //        list.add(new Pair<>(user, distance));
    //    }
    //    // 按编辑距离由小到大排序
    //    List<Pair<User, Long>> topUserPairList = list.stream()
    //            .sorted((a, b) -> (int) (a.getValue() - b.getValue()))
    //            .limit(num)
    //            .collect(Collectors.toList());
    //    // 原本顺序的 userId 列表
    //    List<Long> userIdList = topUserPairList.stream().map(pair -> pair.getKey().getId()).collect(Collectors.toList());
    //    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
    //    userQueryWrapper.in("id", userIdList);
    //    // 1, 3, 2
    //    // User1、User2、User3
    //    // 1 => User1, 2 => User2, 3 => User3
    //    Map<Long, List<User>> userIdUserListMap = this.list(userQueryWrapper)
    //            .stream()
    //            .map(user -> getSafetyUser(user))
    //            .collect(Collectors.groupingBy(User::getId));
    //    List<User> finalUserList = new ArrayList<>();
    //    for (String userId : userIdList) {
    //        finalUserList.add(userIdUserListMap.get(userId).get(0));
    //    }
    //    return finalUserList;
    //}
}




